/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package org.springblade.modules.admin.service.impl;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.apache.poi.xssf.usermodel.*;
import org.springblade.common.utils.CommonUtil;
import org.springblade.common.utils.PoiExcelUtil;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.mp.base.BaseEntity;
import org.springblade.core.mp.base.BaseServiceImpl;
import org.springblade.core.redis.cache.BladeRedis;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tenant.annotation.TenantIgnore;
import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.StringPool;
import org.springblade.core.tool.utils.StringUtil;
import org.springblade.modules.admin.dto.ElevatorSaveDto;
import org.springblade.modules.admin.entity.*;
import org.springblade.modules.admin.entity.es.ElevatorDocument;
import org.springblade.modules.admin.mapper.ElevatorDetailMapper;
import org.springblade.modules.admin.mapper.es.ElevatorDocumentMapper;
import org.springblade.modules.admin.service.*;
import org.springblade.modules.admin.utils.GenerateElevatorNumService;
import org.springblade.modules.admin.vo.ElevatorDetailVO;
import org.springblade.modules.admin.vo.ElevatorVO;
import org.springblade.modules.system.entity.Dict;
import org.springblade.modules.system.entity.Tenant;
import org.springblade.modules.system.service.ITenantService;
import org.springblade.modules.system.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;


/**
 * 服务实现类
 *
 * @author BladeX
 * @since 2021-05-10
 */
@Service
public class ElevatorDetailServiceImpl extends BaseServiceImpl<ElevatorDetailMapper, ElevatorDetail> implements IElevatorDetailService {

	@Autowired
	private ElevatorService elevatorService;
	@Autowired
	private ElevatorPlanStatusService elevatorPlanStatusService;
	@Autowired
	private IElevatorBrandService elevatorBrandService;
	@Autowired
	private ElevatorDriveModeService elevatorDriveModeService;
	@Autowired
	private ITenantService tenantService;
	@Autowired
	private IUserService userService;
	@Autowired
	private BuildingElevatorTemplateService buildingElevatorTemplateService;
	@Autowired
	private BuildingElevatorTemplateReleService buildingElevatorTemplateReleService;
	@Autowired
	private BladeRedis bladeRedis;
	@Autowired
	private GenerateElevatorNumService gens;
	@Autowired
	private IElevatorFieldVService elevatorFieldVService;
	@Autowired
	private IElevatorExtService elevatorExtService;
	@Autowired
	private ElevatorAuditService elevatorAuditService;
	@Autowired
	private Environment environment;
	@Autowired
	private ElevatorDocumentMapper elevatorDocumentMapper;
	@Autowired
	private InsuranceCompanyService insuranceCompanyService;

	private static final String PRIVATE_NUM_AUTO = "00000000000000000000";
	private static final String EXCEL_ERR_CACHE = "elevator:excel:err:";

	@Override
	public IPage<ElevatorDetailVO> selectElevatorDetailPage(IPage<ElevatorDetailVO> page, ElevatorDetailVO elevatorDetail) {
		return page.setRecords(baseMapper.selectElevatorDetailPage(page, elevatorDetail));
	}

	@Override
	public void downExcelDetail(ElevatorVO elevator, List<List<String>> rows) {
		List<ElevatorSaveDto> list = baseMapper.downExcelDetail(elevator);
		list.forEach(elevatorDetail -> {
			List<String> row = new ArrayList<>(11);
			row.add(Convert.toStr(elevatorDetail.getBuildingName()));
			row.add(Convert.toStr(elevatorDetail.getAddress()));
			row.add(Convert.toStr(elevatorDetail.getElevatorAddress()));
			row.add(Convert.toStr(elevatorDetail.getElevatorAlias()));
			row.add(Convert.toStr(elevatorDetail.getPrivateNum()));
			row.add(Convert.toStr(elevatorDetail.getElevatorNum()));
			row.add(Convert.toStr(elevatorDetail.getBrandName()));
			row.add(Convert.toStr(elevatorDetail.getRegisterNumber()));
			row.add(Convert.toStr(elevatorDetail.getEquipmentRegisterNumber()));
			if (StrUtil.isEmpty(elevatorDetail.getSpeed())) {
				row.add("/");
			} else {
				row.add(Convert.toStr(elevatorDetail.getSpeed(), "0") + "m/s");
			}
			if (StrUtil.isEmpty(elevatorDetail.getSupportingPower())) {
				row.add("/");
			} else {
				row.add(Convert.toStr(elevatorDetail.getSupportingPower()) + "kg");
			}

			row.add(Convert.toStr(elevatorDetail.getFloorHigh()));
			row.add(Convert.toStr(elevatorDetail.getStand()));
			row.add(Convert.toStr(elevatorDetail.getDoor()));
			row.add(Convert.toStr(Convert.toInt(elevatorDetail.getIsStop(), 1) == 1 ? "正常" : "停梯"));
			row.add(Convert.toStr(Convert.toInt(elevatorDetail.getUseType(), 1) == 0 ? "年审" : "非年审"));
			rows.add(row);
		});
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public Map<String, Object> uploadExcel(List<Map<String, Object>> readAll, Long buildingId, Long elevatorTemplateId, Integer elevatorUseType) {
		BuildingElevatorTemplate elevatorTemplate = buildingElevatorTemplateService.getById(elevatorTemplateId);
		if (Func.isEmpty(elevatorTemplate) || !buildingId.equals(elevatorTemplate.getBuildingId())) {
			throw new ServiceException("导入模板不正确，请以当前项目的模板进行批量导入");
		}

		Map<String, Object> resultInfo = new HashMap<>(8);
		List<HashMap<String, String>> privateNumList = new ArrayList<>();
		LinkedList<Map<String, Object>> errList = new LinkedList<>();
		int errNum = 0;

		OUT:
		for (int i = 0; i < readAll.size(); i++) {
			HashMap<String, String> errMap = new HashMap<>(4);
			Map<String, Object> excelItemMap = readAll.get(i);
			errList.addLast(excelItemMap);

			Elevator elevator = new Elevator();
			Tenant tenant = tenantService.getByTenantId(AuthUtil.getTenantId());
			elevator.setSourceTenantId(AuthUtil.getTenantId());
			elevator.setSourceTenantName(tenant.getTenantName());
			elevator.setSourceType(tenant.getCompanyCategory());
			elevator.setSourceUserName(userService.getById(AuthUtil.getUserId()).getRealName());
			elevator.setBuildingId(buildingId);
			ElevatorDetail elevatorDetail = new ElevatorDetail();

			// 电梯位置
			int level = elevatorTemplate.getLevel();
			String[] templateNames = elevatorTemplate.getName().split("/");
			String[] releValue = new String[level];
			StringBuilder elevatorAddress = new StringBuilder();
			for (int j = 0; j < level; j++) {
				String addressTitle = BuildingElevatorTemplateService.NULL_TEMPLATE.equals(templateNames[j]) ? "自定义输入" : templateNames[j];
				String columnValue = Convert.toStr(excelItemMap.get(String.format("%s（%d级）", addressTitle, j + 1)));
				if (Func.isBlank(columnValue)) {
					errMap.put("num", String.format("第%d条数据出错", i + 1));
					errMap.put("privateNum", Convert.toStr(excelItemMap.get("设备代码")));
					errMap.put("errMsg", "电梯位置不能为空，请检查导入内容！");
					privateNumList.add(errMap);
					errNum++;
					continue OUT;
				}
				releValue[j] = columnValue;
				elevatorAddress.append(columnValue);
				if (!BuildingElevatorTemplateService.NULL_TEMPLATE.equals(templateNames[j])) {
					elevatorAddress.append(templateNames[j]);
				}
			}
			// 校验电梯位置是否重复
			if (baseMapper.checkElevatorAddress(elevatorTemplateId, elevatorAddress.toString()) > 0) {
				errMap.put("num", String.format("第%d条数据出错", i + 1));
				errMap.put("privateNum", Convert.toStr(excelItemMap.get("设备代码")));
				errMap.put("errMsg", "电梯位置已存在！");
				privateNumList.add(errMap);
				errNum++;
				continue;
			}
			String releIds = buildingElevatorTemplateReleService.saveRele(elevatorTemplateId, releValue);
			elevator.setReleIds(releIds);
			elevator.setTemplateId(elevatorTemplateId);
			elevatorDetail.setElevatorAddress(elevatorAddress.toString());

			// 设备代码
			String privateNum = Convert.toStr(excelItemMap.get("设备注册代码"));

			//新增出厂编号和保险公司
			String factoryNumber = Convert.toStr(excelItemMap.get("出厂编号"));
			elevatorDetail.setFactoryNumber(factoryNumber);
			String bxCompanyName = Convert.toStr(excelItemMap.get("保险公司"));
			String sourceStatusName = Convert.toStr(excelItemMap.get("电梯来源"), "安装");
			String lifeStatusName = Convert.toStr(excelItemMap.get("生命周期"), "未注册");
			if (sourceStatusName.equals("安装")) {
				elevator.setSourceStatus("1");
			} else {
				elevator.setSourceStatus("2");
			}
			if (sourceStatusName.equals("安装") && StrUtil.isEmpty(Convert.toStr(excelItemMap.get("电梯来源公司")))) {
				elevator.setSourceDesc("中山市银河机电有限公司");
			} else {
				elevator.setSourceDesc(Convert.toStr(excelItemMap.get("电梯来源公司")));
			}
			if (lifeStatusName.equals("未注册")) {
				elevator.setLifeStatus(1);
			} else if (lifeStatusName.equals("在用")) {
				elevator.setLifeStatus(2);
			} else if (lifeStatusName.equals("停用")) {
				elevator.setLifeStatus(3);
			} else if (lifeStatusName.equals("安装改造维修中")) {
				elevator.setLifeStatus(4);
			} else if (lifeStatusName.equals("注销")) {
				elevator.setLifeStatus(5);
			} else {
				elevator.setLifeStatus(6);
			}
			InsuranceCompany insuranceCompany = insuranceCompanyService.getOne(Wrappers.<InsuranceCompany>lambdaQuery().eq(InsuranceCompany::getName, bxCompanyName).last("limit 1"));
			if (insuranceCompany != null) {
				elevator.setBxCompanyId(insuranceCompany.getId());
			}
			// 2025-08 新增详细地址以及保险到期日期
			String locationAddressStr = Convert.toStr(excelItemMap.get("详细地址"));
			if (Func.isBlank(locationAddressStr)) {
				errMap.put("num", String.format("第%d条数据出错", i + 1));
				errMap.put("privateNum", privateNum);
				errMap.put("errMsg", "详细地址不能为空，请检查导入内容！");
				privateNumList.add(errMap);
				errNum++;
				continue;
			}
			elevatorDetail.setLocationAddress(locationAddressStr);
			String dateStr = Convert.toStr(excelItemMap.get("保险到期日期"));
			// 根据yyyy-MM-dd格式转换为日期
			Date bxCompanyEndDate = null;
			if (StringUtil.isNotBlank(dateStr)) {
				try {
					bxCompanyEndDate = DateUtil.parse(dateStr, "yyyy-MM-dd");
				} catch (Exception e) {
					log.warn("日期格式转换失败，请检查导入内容！");
					throw new ServiceException("日期格式转换失败，请检查导入内容！");
				}
			}
			elevator.setBxCompanyEndDate(bxCompanyEndDate);

			if (Func.isNotBlank(privateNum) && !PRIVATE_NUM_AUTO.equals(privateNum)) {
				int count = elevatorService.count(Wrappers.<Elevator>lambdaQuery().eq(Elevator::getPrivateNum, privateNum));
				if (privateNum.length() > 20 || privateNum.length() < 4) {
					errMap.put("num", String.format("第%d条数据出错", i + 1));
					errMap.put("privateNum", privateNum);
					errMap.put("errMsg", "设备代码格式异常，请检查导入内容！");
					privateNumList.add(errMap);
					errNum++;
					continue;
				}
				if (count > 0) {
					errMap.put("num", String.format("第%d条数据出错", i + 1));
					errMap.put("privateNum", privateNum);
					errMap.put("errMsg", "设备代码重复，请检查导入内容！");
					privateNumList.add(errMap);
					errNum++;
					continue;
				}
				elevator.setPrivateNum(privateNum);

				// 制造日期
//				Date madeDate = null;
//				try {
//					madeDate = DateUtil.parse(privateNum.substring(10,16),"yyyyMM");
//				}catch (Exception e){
//					errMap.put("num", String.format("第%d条数据出错", i + 1));
//					errMap.put("privateNum",privateNum);
//					errMap.put("errMsg","设备代码格式异常，请检查导入内容！");
//					privateNumList.add(errMap);
//					errNum++;
//					continue;
//				}
//				elevatorDetail.setMadeDate(madeDate);
			}

			// 根据设备代码生成电梯驱动方式
			ElevatorDriveMode elevatorDriveMode = elevatorDriveModeService.getOne(Wrappers.<ElevatorDriveMode>lambdaQuery().eq(ElevatorDriveMode::getName, Convert.toStr(excelItemMap.get("设备品种"))));
			if (ObjectUtil.isNotEmpty(elevatorDriveMode)) {
				elevatorDetail.setElevatorUseType(elevatorDriveMode.getId());
			} else {
				errMap.put("num", String.format("第%d条数据出错", i + 1));
				errMap.put("privateNum", privateNum);
				errMap.put("errMsg", "设备品种不存在，请检查导入内容！");
				privateNumList.add(errMap);
				errNum++;
				continue;
			}

			// 电梯年检类型
			String useType = Convert.toStr(excelItemMap.get("电梯年检类型"));
			if (ObjectUtil.isEmpty(useType) || !(useType.equals("年审梯") || useType.equals("非年审梯"))) {
				errMap.put("num", String.format("第%d条数据出错", i + 1));
				errMap.put("privateNum", privateNum);
				errMap.put("errMsg", "电梯年检类型填写错误，请检查导入内容！");
				privateNumList.add(errMap);
				errNum++;
				continue;
			}
			elevatorDetail.setUseType(useType.equals("年审梯") ? 0 : 1);

			// 电梯品牌
			ElevatorBrand elevatorBrand = elevatorBrandService.getOne(Wrappers.<ElevatorBrand>lambdaQuery().eq(ElevatorBrand::getBrandName, Convert.toStr(excelItemMap.get("电梯品牌"))), false);
			if (ObjectUtil.isEmpty(elevatorBrand)) {
				errMap.put("num", String.format("第%d条数据出错", i + 1));
				errMap.put("privateNum", privateNum);
				errMap.put("errMsg", "品牌名称不存在，请检查导入内容！");
				privateNumList.add(errMap);
				errNum++;
				continue;
			}
			elevator.setBrandId(elevatorBrand.getId());
			elevator.setBrandName(elevatorBrand.getBrandName());

			// 服务电话
			String wbPhone = Convert.toStr(excelItemMap.get("服务电话"));
			if (ObjectUtil.isEmpty(wbPhone)) {
				errMap.put("num", String.format("第%d条数据出错", i + 1));
				errMap.put("privateNum", privateNum);
				errMap.put("errMsg", "服务电话不存在，请检查导入内容！");
				privateNumList.add(errMap);
				errNum++;
				continue;
			}
			elevator.setWbPhone(wbPhone);


			// 单位内编号
			String registerNumber = Convert.toStr(excelItemMap.get("单位内编号"));
//			if(ObjectUtil.isEmpty(registerNumber)){
//				errMap.put("num", String.format("第%d条数据出错", i + 1));
//				errMap.put("privateNum",privateNum);
//				errMap.put("errMsg","单位内编号不存在，请检查导入内容！");
//				privateNumList.add(errMap);
//				errNum++;
//				continue;
//			}
			elevatorDetail.setRegisterNumber(registerNumber);

			// 登记证编号
			String equipmentRegisterNumber = Convert.toStr(excelItemMap.get("登记证编号"));
//			if(ObjectUtil.isEmpty(equipmentRegisterNumber)){
//				errMap.put("num", String.format("第%d条数据出错", i + 1));
//				errMap.put("privateNum",privateNum);
//				errMap.put("errMsg","登记证编号不存在，请检查导入内容！");
//				privateNumList.add(errMap);
//				errNum++;
//				continue;
//			}
			elevatorDetail.setEquipmentRegisterNumber(equipmentRegisterNumber);

			// 设备技术参数字段
			ElevatorFieldV fieldV = new ElevatorFieldV();
			// 额定速度
			if (null != excelItemMap.get("额定速度(m/s)")) {
				String speed = Convert.toStr(excelItemMap.get("额定速度(m/s)"));
				if (ObjectUtil.isEmpty(speed)) {
					errMap.put("num", String.format("第%d条数据出错", i + 1));
					errMap.put("privateNum", privateNum);
					errMap.put("errMsg", "额定速度不存在，请检查导入内容！");
					privateNumList.add(errMap);
					errNum++;
					continue;
				}
				elevatorDetail.setSpeed(speed);
				fieldV.setRatedSpeed(speed);
			}

			// 额定载重量
			if (null != excelItemMap.get("额定载重量(kg)")) {
				String supportingPower = Convert.toStr(excelItemMap.get("额定载重量(kg)"));
				if (ObjectUtil.isEmpty(supportingPower)) {
					errMap.put("num", String.format("第%d条数据出错", i + 1));
					errMap.put("privateNum", privateNum);
					errMap.put("errMsg", "额定载重量不存在，请检查导入内容！");
					privateNumList.add(errMap);
					errNum++;
					continue;
				}
				elevatorDetail.setSupportingPower(supportingPower);
				fieldV.setRatedWeight(supportingPower);
			}

			// 层
			if (null != excelItemMap.get("层")) {
				String floorHigh = Convert.toStr(excelItemMap.get("层"));
				if (ObjectUtil.isEmpty(floorHigh)) {
					errMap.put("num", String.format("第%d条数据出错", i + 1));
					errMap.put("privateNum", privateNum);
					errMap.put("errMsg", "层不存在，请检查导入内容！");
					privateNumList.add(errMap);
					errNum++;
					continue;
				}
				elevatorDetail.setFloorHigh(floorHigh);
				fieldV.setTier(floorHigh);
			}

			// 站
			if (null != excelItemMap.get("站")) {
				String stand = Convert.toStr(excelItemMap.get("站"));
				if (ObjectUtil.isEmpty(stand)) {
					errMap.put("num", String.format("第%d条数据出错", i + 1));
					errMap.put("privateNum", privateNum);
					errMap.put("errMsg", "站不存在，请检查导入内容！");
					privateNumList.add(errMap);
					errNum++;
					continue;
				}
				elevatorDetail.setStand(stand);
				fieldV.setStand(stand);
			}

			// 门
			if (null != excelItemMap.get("门")) {
				String door = Convert.toStr(excelItemMap.get("门"));
				if (ObjectUtil.isEmpty(door)) {
					errMap.put("num", String.format("第%d条数据出错", i + 1));
					errMap.put("privateNum", privateNum);
					errMap.put("errMsg", "门不存在，请检查导入内容！");
					privateNumList.add(errMap);
					errNum++;
					continue;
				}
				elevatorDetail.setDoor(door);
				fieldV.setDoor(door);
			}

			// 防爆标志
			if (null != excelItemMap.get("防爆标志")) {
				String antiExplosionMark = Convert.toStr(excelItemMap.get("防爆标志"));
				if (ObjectUtil.isEmpty(antiExplosionMark)) {
					errMap.put("num", String.format("第%d条数据出错", i + 1));
					errMap.put("privateNum", privateNum);
					errMap.put("errMsg", "防爆标志不存在，请检查导入内容！");
					privateNumList.add(errMap);
					errNum++;
					continue;
				}
				fieldV.setAntiExplosionMark(String.valueOf(antiExplosionMark));
			}

			// 区域防爆等级
			if (null != excelItemMap.get("区域防爆等级")) {
				List<Dict> dictList = elevatorService.driverModeFieldSelect("antiExplosionLevel", null, null);
				Map<String, String> dictMap = dictList.stream().collect(Collectors.toMap(Dict::getDictValue, Dict::getDictKey));
				String antiExplosionLevel = Convert.toStr(excelItemMap.get("区域防爆等级"));
				if (ObjectUtil.isEmpty(antiExplosionLevel)) {
					errMap.put("num", String.format("第%d条数据出错", i + 1));
					errMap.put("privateNum", privateNum);
					errMap.put("errMsg", "区域防爆等级不存在，请检查导入内容！");
					privateNumList.add(errMap);
					errNum++;
					continue;
				}
				fieldV.setAntiExplosionLevel(dictMap.get(antiExplosionLevel));
			}

			// 额定速度(m/s)上行
			if (null != excelItemMap.get("额定速度(m/s)上行")) {
				String ratedSpeedUp = Convert.toStr(excelItemMap.get("额定速度(m/s)上行"));
				if (ObjectUtil.isEmpty(ratedSpeedUp)) {
					errMap.put("num", String.format("第%d条数据出错", i + 1));
					errMap.put("privateNum", privateNum);
					errMap.put("errMsg", "额定速度(m/s)上行不存在，请检查导入内容！");
					privateNumList.add(errMap);
					errNum++;
					continue;
				}
				fieldV.setRatedSpeedUp(ratedSpeedUp);
			}

			// 额定速度(m/s)下行
			if (null != excelItemMap.get("额定速度(m/s)下行")) {
				String ratedSpeedDown = Convert.toStr(excelItemMap.get("额定速度(m/s)下行"));
				if (ObjectUtil.isEmpty(ratedSpeedDown)) {
					errMap.put("num", String.format("第%d条数据出错", i + 1));
					errMap.put("privateNum", privateNum);
					errMap.put("errMsg", "额定速度(m/s)下行不存在，请检查导入内容！");
					privateNumList.add(errMap);
					errNum++;
					continue;
				}
				fieldV.setRatedSpeedDown(ratedSpeedDown);
			}

			// 油缸数量
			if (null != excelItemMap.get("油缸数量")) {
				String oilCylinderNum = Convert.toStr(excelItemMap.get("油缸数量"));
				if (ObjectUtil.isEmpty(oilCylinderNum)) {
					errMap.put("num", String.format("第%d条数据出错", i + 1));
					errMap.put("privateNum", privateNum);
					errMap.put("errMsg", "油缸数量不存在，请检查导入内容！");
					privateNumList.add(errMap);
					errNum++;
					continue;
				}
				fieldV.setOilCylinderNum(oilCylinderNum);
			}

			// 名义速度(m/s)
			if (null != excelItemMap.get("名义速度(m/s)")) {
				String nominalSpeed = Convert.toStr(excelItemMap.get("名义速度(m/s)"));
				if (ObjectUtil.isEmpty(nominalSpeed)) {
					errMap.put("num", String.format("第%d条数据出错", i + 1));
					errMap.put("privateNum", privateNum);
					errMap.put("errMsg", "名义速度(m/s)不存在，请检查导入内容！");
					privateNumList.add(errMap);
					errNum++;
					continue;
				}
				fieldV.setNominalSpeed(nominalSpeed);
			}

			// 名义宽度(mm)
			if (null != excelItemMap.get("名义宽度(mm)")) {
				String nominalWidth = Convert.toStr(excelItemMap.get("名义宽度(mm)"));
				if (ObjectUtil.isEmpty(nominalWidth)) {
					errMap.put("num", String.format("第%d条数据出错", i + 1));
					errMap.put("privateNum", privateNum);
					errMap.put("errMsg", "名义宽度(mm)不存在，请检查导入内容！");
					privateNumList.add(errMap);
					errNum++;
					continue;
				}
				fieldV.setNominalWidth(nominalWidth);
			}

			// 倾斜角(°)
			if (null != excelItemMap.get("倾斜角(°)")) {
				String inclineAngle = Convert.toStr(excelItemMap.get("倾斜角(°)"));
				if (ObjectUtil.isEmpty(inclineAngle)) {
					errMap.put("num", String.format("第%d条数据出错", i + 1));
					errMap.put("privateNum", privateNum);
					errMap.put("errMsg", "倾斜角(°)不存在，请检查导入内容！");
					privateNumList.add(errMap);
					errNum++;
					continue;
				}
				fieldV.setInclineAngle(inclineAngle);
			}

			// 输送能力
			if (null != excelItemMap.get("输送能力(p/h)")) {
				String transportCapacity = Convert.toStr(excelItemMap.get("输送能力(p/h)"));
				if (ObjectUtil.isEmpty(transportCapacity)) {
					errMap.put("num", String.format("第%d条数据出错", i + 1));
					errMap.put("privateNum", privateNum);
					errMap.put("errMsg", "输送能力不存在，请检查导入内容！");
					privateNumList.add(errMap);
					errNum++;
					continue;
				}
				fieldV.setTransportCapacity(transportCapacity);
			}

			// 提升高度
			if (null != excelItemMap.get("提升高度(m)")) {
				String promoteHeight = Convert.toStr(excelItemMap.get("提升高度(m)"));
				if (ObjectUtil.isEmpty(promoteHeight)) {
					errMap.put("num", String.format("第%d条数据出错", i + 1));
					errMap.put("privateNum", privateNum);
					errMap.put("errMsg", "提升高度不存在，请检查导入内容！");
					privateNumList.add(errMap);
					errNum++;
					continue;
				}
				fieldV.setPromoteHeight(promoteHeight);
			}

			// 使用区域长度(m)
			if (null != excelItemMap.get("使用区域长度(m)")) {
				String zoneLength = Convert.toStr(excelItemMap.get("使用区域长度(m)"));
				if (ObjectUtil.isEmpty(zoneLength)) {
					errMap.put("num", String.format("第%d条数据出错", i + 1));
					errMap.put("privateNum", privateNum);
					errMap.put("errMsg", "使用区域长度(m)不存在，请检查导入内容！");
					privateNumList.add(errMap);
					errNum++;
					continue;
				}
				fieldV.setZoneLength(zoneLength);
			}

			// 控制方式
			if (null != excelItemMap.get("控制方式")) {
				if (StringUtil.isEmpty(String.valueOf(excelItemMap.get("控制方式")))) {
					errMap.put("num", String.format("第%d条数据出错", i + 1));
					errMap.put("privateNum", privateNum);
					errMap.put("errMsg", "控制方式不存在，请检查导入内容！");
					privateNumList.add(errMap);
					errNum++;
					continue;
				}
				String driverModeCode = elevatorDriveMode.getCode();
				String code = "controlMode";
				String driverModeKey = "1";
				if (elevatorUseType == 2 || elevatorUseType == 6) {
					driverModeKey = "3";
				}
				List<Dict> dictList = elevatorService.driverModeFieldSelect(code, driverModeCode, driverModeKey);
				String controlMode = Convert.toStr(excelItemMap.get("控制方式"));
				Map<String, String> dictMap = dictList.stream().collect(Collectors.toMap(Dict::getDictValue, Dict::getDictKey));
				if (ObjectUtil.isEmpty(controlMode)) {
					errMap.put("num", String.format("第%d条数据出错", i + 1));
					errMap.put("privateNum", privateNum);
					errMap.put("errMsg", "控制方式不存在，请检查导入内容！");
					privateNumList.add(errMap);
					errNum++;
					continue;
				}
				fieldV.setControlMode(dictMap.get(controlMode));
				String driverMode = driverModeCode.equals("3420") && elevatorUseType == 1 ? "2" : driverModeKey;
				fieldV.setDriverMode(driverMode);
			}

			// 顶升方式
			if (null != excelItemMap.get("顶升方式")) {
				if (StringUtil.isEmpty(String.valueOf(excelItemMap.get("顶升方式")))) {
					errMap.put("num", String.format("第%d条数据出错", i + 1));
					errMap.put("privateNum", privateNum);
					errMap.put("errMsg", "顶升方式不存在，请检查导入内容！");
					privateNumList.add(errMap);
					errNum++;
					continue;
				}
				List<Dict> dictList = elevatorService.driverModeFieldSelect("jackingForm", null, null);
				Map<String, String> dictMap = dictList.stream().collect(Collectors.toMap(Dict::getDictValue, Dict::getDictKey));
				String jackingForm = Convert.toStr(excelItemMap.get("顶升方式"));
				if (ObjectUtil.isEmpty(jackingForm)) {
					errMap.put("num", String.format("第%d条数据出错", i + 1));
					errMap.put("privateNum", privateNum);
					errMap.put("errMsg", "顶升方式不存在，请检查导入内容！");
					privateNumList.add(errMap);
					errNum++;
					continue;
				}
				fieldV.setJackingForm(dictMap.get(jackingForm));
			}

			elevatorService.save(elevator);
			elevatorDetail.setElevatorId(elevator.getId());
			fieldV.setElevatorId(elevator.getId());
			elevatorFieldVService.save(fieldV);
			ElevatorExt elevatorExt = new ElevatorExt();
			elevatorExt.setElevatorId(elevator.getId());
			elevatorExtService.save(elevatorExt);
			if (this.save(elevatorDetail)) {
				// 电梯导入成功，从错误集合移除
				errList.removeLast();
			}

			// 新增 导入电梯随即设置唯一码识别，并插入至Detail对象
			String elevatorNum = gens.generateElevatorNum(elevator.getId());
			elevatorDetail.setElevatorNum(elevatorNum);
			// 执行更新 插入电梯码
			this.updateById(elevatorDetail);

			//当前环境
			String curEnvironment = environment.getActiveProfiles()[0];
			if (Func.equalsSafe(curEnvironment, "prod")) {
				// 插入小程序码
				String wxAppCodeUrl = elevatorService.generateWxAppCode(elevator.getId());
				if (Func.isNotBlank(wxAppCodeUrl)) {
					elevator.setWxAppCodeUrl(wxAppCodeUrl);
					elevatorService.updateById(elevator);
				}
			}

			ElevatorPlanStatus elevatorPlanStatus = new ElevatorPlanStatus();
			elevatorPlanStatus.setElevatorId(elevator.getId());
			elevatorPlanStatusService.save(elevatorPlanStatus);

			// 2025-06-19 电梯搜索插入ES
			ElevatorDocument document = new ElevatorDocument();
			document.setId(elevator.getId());
			document.setName(elevatorDetail.getElevatorAddress());
			document.setNamePinyin(elevatorDetail.getElevatorAddress());
			document.setAlias(elevatorDetail.getElevatorAlias());
			document.setAliasPinyin(elevatorDetail.getElevatorAlias());
			document.setBuildingId(elevator.getBuildingId());
			document.setTenantId(tenant.getTenantId());
			elevatorDocumentMapper.insert(document);
		}

		// 处理电梯年检时间
//		elevatorService.auditTimeTask(elevatorList);

		// 将出错数据存到redis
		if (errNum > 0) {
			bladeRedis.setEx(AuthUtil.getTenantId().concat(StringPool.COLON).concat(EXCEL_ERR_CACHE).concat(String.format("%s-%s", buildingId, elevatorTemplateId)), errList, 30000L);
		}

		if (privateNumList.isEmpty()) {
			resultInfo.put("result", Boolean.TRUE);
		} else {
			resultInfo.put("result", Boolean.FALSE);
		}
		resultInfo.put("total", readAll.size());
		resultInfo.put("succeed", readAll.size() - errNum);
		resultInfo.put("untreated", privateNumList);
		resultInfo.put("elevatorTemplateId", elevatorTemplateId);
		return resultInfo;
	}

	@Override
	public void downErrElevatorExcel(HttpServletResponse response, Long elevatorTemplateId, Long buildingId, Integer elevatorUseType) {
		BuildingElevatorTemplate elevatorTemplate = buildingElevatorTemplateService.getById(elevatorTemplateId);
		if (Func.isEmpty(elevatorTemplate)) {
			throw new ServiceException("电梯模板不存在！");
		}

		Object data = bladeRedis.get(AuthUtil.getTenantId().concat(StringPool.COLON).concat(EXCEL_ERR_CACHE).concat(String.format("%s-%s", buildingId, elevatorTemplateId)));
		if (Func.isEmpty(data)) {
			throw new ServiceException("未有错误数据导出！");
		}
		LinkedList<Map<String, Object>> errList = (LinkedList<Map<String, Object>>) data;

		XSSFWorkbook workbook = this.initExcelTemplate(elevatorTemplate, elevatorUseType);
		XSSFSheet sheet = workbook.getSheetAt(0);
		Map<String, Object> titleMap = PoiExcelUtil.getRowData(sheet, sheet.getRow(2), null);

		for (int i = 0; i < errList.size(); i++) {
			Map<String, Object> itemMap = errList.get(i);
			XSSFRow row = sheet.createRow(i + 3);
			row.setHeightInPoints(20);
			titleMap.forEach((tKey, tValue) -> {
				XSSFCell cell = row.createCell(Integer.parseInt(tKey));
				cell.setCellValue(Convert.toStr(itemMap.get(tValue)));
			});
		}
		String fileName = "error-" + DateUtil.format(new Date(), "yyyyMMddHHmmss") + ".xlsx";
		ServletOutputStream outputStream = null;
		try {
			outputStream = response.getOutputStream();
			CommonUtil.setResponseHeader(response, fileName);
			workbook.write(outputStream);
			outputStream.flush();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (workbook != null) {
					workbook.close();
				}
				outputStream.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	@Override
	public Boolean uploadExcelTem(List<Map<String, Object>> readAll) {
		readAll = readAll.stream().filter(e -> Func.isNotEmpty(e.get("单位内部编号"))).collect(Collectors.toList());
		List<String> registerNumber = readAll.stream().map(e -> String.valueOf(e.get("单位内部编号"))).collect(Collectors.toList());
		List<ElevatorDetail> elevatorDetailList = super.list(Wrappers.<ElevatorDetail>lambdaQuery().in(ElevatorDetail::getRegisterNumber, registerNumber));
		if (Func.isNotEmpty(elevatorDetailList)) {
			List<Map<String, Object>> finalReadAll = readAll;

			List<Elevator> elevatorList = new ArrayList<>();
			List<ElevatorAudit> elevatorAudits = new ArrayList<>();
			elevatorDetailList.forEach(e -> {
				finalReadAll.forEach(j -> {
					if (e.getRegisterNumber().equals(String.valueOf(j.get("单位内部编号")))) {
						Elevator elevator = new Elevator();
						elevator.setId(e.getElevatorId());
						if (Func.isNotEmpty(j.get("设备注册代码")) && String.valueOf(j.get("设备注册代码")).length() == 20) {
							elevator.setPrivateNum(String.valueOf(j.get("设备注册代码")));
							e.setStartDate(DateUtil.parse(String.valueOf(j.get("设备注册代码")).substring(10, 16), "yyyyMM"));
						}
						if (Func.isNotEmpty(j.get("定期下检日期"))) {
							if (DateUtil.parse(String.valueOf(j.get("定期下检日期"))).getTime() > DateUtil.parse(DateUtil.today()).getTime()) {
								elevator.setElevatorAudit(String.valueOf(j.get("定期下检日期")));
								ElevatorAudit audit = new ElevatorAudit();
								audit.setElevatorId(e.getElevatorId());
								audit.setAuditTime(String.valueOf(j.get("定期下检日期")));
								elevatorAudits.add(audit);
							}
						}
						elevatorList.add(elevator);
					}
				});
			});

			if (Func.isNotEmpty(elevatorList)) {
				List<List<Elevator>> elevators = ListUtil.partition(elevatorList, 100);
				elevators.forEach(e -> elevatorService.updateBatchById(e));
			}

			if (Func.isNotEmpty(elevatorAudits)) {
				List<ElevatorAudit> elevatorAuditList = elevatorAuditService.list(Wrappers.<ElevatorAudit>lambdaQuery().in(ElevatorAudit::getElevatorId, elevatorAudits.stream().map(ElevatorAudit::getElevatorId).collect(Collectors.toList())));
				if (Func.isNotEmpty(elevatorAuditList)) {
					elevatorAuditList.forEach(e -> {
						elevatorAudits.forEach(j -> {
							if (e.getElevatorId().equals(j.getElevatorId())) {
								e.setAuditTime(j.getAuditTime());
							}
						});
					});
				}
				List<List<ElevatorAudit>> elevatorAuditLists = ListUtil.partition(elevatorAuditList, 100);
				elevatorAuditLists.forEach(e -> elevatorAuditService.updateBatchById(e));
			}

			List<List<ElevatorDetail>> elevatorDetails = ListUtil.partition(elevatorDetailList, 100);
			elevatorDetails.forEach(super::updateBatchById);
		}
		System.err.println(readAll.size());
		return Boolean.TRUE;
	}

	@Override
	@TenantIgnore
	public ElevatorDetail getByElevatorAddress(String roomId, String elevatorAddress) {
		List<ElevatorDetail> list = baseMapper.selectByRoomIdAndElevatorAddress(roomId, elevatorAddress);
		if (Func.isEmpty(list)) {
			return null;
		}
		return list.get(0);
	}

	@Override
	public List<ElevatorDetail> listAll() {
		return baseMapper.listAll();
	}

	/**
	 * 初始化excel标题栏
	 *
	 * @param level
	 * @param elevatorTemplateName
	 * @return
	 */
	private Map<Integer, String> intiExcelTitle(int level, String elevatorTemplateName) {
		Map<Integer, String> titleMap = new LinkedHashMap<>(16);
		// 固定标题
		String[] fixedTitle = {"设备注册代码", "设备品种", "电梯年检类型", "电梯品牌", "单位内编号", "服务电话", "单位内编号", "登记证编号", "额定速度(m/s)", "额定载重量(kg)", "层", "站", "门"};
		// 动态标题
		String[] templateNames = elevatorTemplateName.split("/");
		for (int i = 0; i < (fixedTitle.length + 5); i++) {
			if (i < level) {
				String addressTitle = BuildingElevatorTemplateService.NULL_TEMPLATE.equals(templateNames[i]) ? "自定义输入" : templateNames[i];
				titleMap.put(i, String.format("%s（%d级）", addressTitle, i + 1));
			} else if (i >= 5) {
				titleMap.put(i, fixedTitle[i - 5]);
			}
		}
		return titleMap;
	}

	@Override
	public void downElevatorTemplate(HttpServletResponse response, Long elevatorTemplateId, Integer elevatorUseType) {
		BuildingElevatorTemplate elevatorTemplate = buildingElevatorTemplateService.getById(elevatorTemplateId);
		if (Func.isEmpty(elevatorTemplate)) {
			throw new ServiceException("电梯模板不存在！");
		}

		XSSFWorkbook workbook = this.initExcelTemplate(elevatorTemplate, elevatorUseType);
		String fileName = DateUtil.format(new Date(), "yyyyMMddHHmmss") + ".xlsx";
		ServletOutputStream outputStream = null;
		try {
			outputStream = response.getOutputStream();
			CommonUtil.setResponseHeader(response, fileName);
			workbook.write(outputStream);
			outputStream.flush();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (workbook != null) {
					workbook.close();
				}
				outputStream.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 初始化excel模板
	 *
	 * @param elevatorTemplate
	 * @param elevatorUseType
	 * @return
	 */
	private XSSFWorkbook initExcelTemplate(BuildingElevatorTemplate elevatorTemplate, Integer elevatorUseType) {
		XSSFWorkbook workbook = null;
		//读取源文件
		ClassPathResource resource;
		try {
			switch (elevatorUseType) {
				case 1:
					resource = new ClassPathResource("templates/曳引与强制驱动电梯.xlsx");
					break;
				case 2:
					resource = new ClassPathResource("templates/液压驱动型电梯.xlsx");
					break;
				case 3:
					resource = new ClassPathResource("templates/自动人行道.xlsx");
					break;
				case 4:
					resource = new ClassPathResource("templates/自动扶梯.xlsx");
					break;
				case 5:
					resource = new ClassPathResource("templates/防爆梯(曳引驱动).xlsx");
					break;
				case 6:
					resource = new ClassPathResource("templates/防爆梯(液压驱动).xlsx");
					break;
				default:
					resource = new ClassPathResource("templates/elevator_template.xlsx");
			}
			workbook = new XSSFWorkbook(resource.getInputStream());
		} catch (IOException e) {
			e.printStackTrace();
			throw new ServiceException("电梯模板文件异常！");
		}

		//进行模板的克隆（接下来的操作都是针对克隆后的sheet）
		XSSFSheet sheet = workbook.cloneSheet(0);
		// 行数
		final int maxRow = 1000;
		// 清空内容
		this.removeRow(sheet, 3, maxRow);

		// 自定义样式
		XSSFCellStyle style = workbook.createCellStyle();
		//自定义颜色对象
		XSSFColor color = new XSSFColor();
		int rgb = CommonUtil.getIntFromColor(217, 217, 217);
		color.setRGB(CommonUtil.intToByteArray(rgb));
		style.setFillForegroundColor(color);
		//前景填充模式
		style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
		// 创建一个居中格式
		style.setAlignment(HorizontalAlignment.CENTER);
		// 垂直居中
		style.setVerticalAlignment(VerticalAlignment.CENTER);
		// 新建一个字体
		XSSFFont whiteFont = workbook.createFont();
		whiteFont.setColor(IndexedColors.BLACK.getIndex());
		whiteFont.setFontHeightInPoints((short) 12);
		style.setFont(whiteFont);

		// 模板最大级数
		int maxLevel = 5;
		// 模板级数
		int level = elevatorTemplate.getLevel();
		String[] templateName = elevatorTemplate.getName().split("/");
		for (int i = 0; i < maxLevel; i++) {
			XSSFRow row = sheet.getRow(2);
			XSSFCell cell = row.createCell(i);
			cell.setCellStyle(style);
			if (i < level) {
				sheet.setColumnHidden(i, false);
				// 模板数据写入
				if (BuildingElevatorTemplateService.NULL_TEMPLATE.equals(templateName[i])) {
					cell.setCellValue(String.format("自定义输入（%d级）", i + 1));
				} else {
					cell.setCellValue(String.format("%s（%d级）", templateName[i], i + 1));
				}
			} else {
				// 赋空
				cell.removeCellComment();
				// 隐藏列
				sheet.setColumnHidden(i, true);
			}
		}

		// 设置品牌下拉选择数据源
//		List<ElevatorBrand> brandList = elevatorBrandService.list(Wrappers.<ElevatorBrand>lambdaQuery().last("limit 45"));
		List<ElevatorBrand> brandList = elevatorBrandService.list();
		String[] brands = brandList.stream().map(ElevatorBrand::getBrandName).toArray(String[]::new);

		//设置一级下拉
		XSSFDataValidationHelper dvHelper = new XSSFDataValidationHelper(sheet);
		XSSFSheet hidden = workbook.createSheet("hidden");
		XSSFCell cell = null;
		for (int i = 0, length = brands.length; i < length; i++) {
			String name = brands[i];
			XSSFRow row = hidden.createRow(i);
			cell = row.createCell(0);
			cell.setCellValue(name);
		}

		String strFormula = "hidden!$A$1:$A$" + brands.length;
		XSSFDataValidationConstraint constraint = new XSSFDataValidationConstraint(DataValidationConstraint.ValidationType.LIST, strFormula);

		// 四个参数分别是：起始行、终止行、起始列、终止列.
		// 1 (一级下拉框代表从excel第1+1行开始) 10(一级下拉框代表从excel第1+10行结束) 1(代表第几列开始，0是第一列，1是第二列) 1(代表第几列结束，0是第一列，1是第二列)
		CellRangeAddressList provinceRangeAddressList = new CellRangeAddressList(3, maxRow, 8, 8);
		DataValidation provinceDataValidation = dvHelper.createValidation(constraint, provinceRangeAddressList);
		provinceDataValidation.createErrorBox("error", "请选择正确数据");
		provinceDataValidation.setShowErrorBox(true);
		sheet.addValidationData(provinceDataValidation);

		XSSFDataValidationHelper phoneDvHelper = new XSSFDataValidationHelper(sheet);
		// 设置下拉服务电话
		List<String> phones = elevatorService.getElevatorPhones();
		for (int j = 0; j < phones.size(); j++) {
			XSSFRow row = hidden.getRow(j);
			if (row == null) {
				row = hidden.createRow(j);
			}
			cell = row.createCell(1);
			cell.setCellValue(phones.get(j));
		}
		String phoneFormula = "hidden!$B$1:$B$" + phones.size();
		XSSFDataValidationConstraint phoneConstraint = new XSSFDataValidationConstraint(DataValidationConstraint.ValidationType.LIST, phoneFormula);
		CellRangeAddressList phoneProvinceRangeAddressList = new CellRangeAddressList(3, maxRow, 12, 12);
		DataValidation phoneProvinceDataValidation = phoneDvHelper.createValidation(phoneConstraint, phoneProvinceRangeAddressList);
		phoneProvinceDataValidation.createErrorBox("error", "请选择正确数据");
		phoneProvinceDataValidation.setShowErrorBox(true);
		sheet.addValidationData(phoneProvinceDataValidation);


		//设置下拉保险公司
		List<String> companyNames = insuranceCompanyService.list().stream().map(InsuranceCompany::getName).collect(Collectors.toList());
		for (int j = 0; j < companyNames.size(); j++) {
			XSSFRow row = hidden.getRow(j);
			if (row == null) {
				row = hidden.createRow(j);
			}
			cell = row.createCell(2);
			cell.setCellValue(companyNames.get(j));
		}
		String companyNameFormula = "hidden!$C$1:$C$" + companyNames.size();
		XSSFDataValidationConstraint companyNameConstraint = new XSSFDataValidationConstraint(DataValidationConstraint.ValidationType.LIST, companyNameFormula);
		CellRangeAddressList companyProvinceRangeAddressList = new CellRangeAddressList(3, maxRow, 13, 13);
		DataValidation companyProvinceDataValidation = phoneDvHelper.createValidation(companyNameConstraint, companyProvinceRangeAddressList);
		companyProvinceDataValidation.createErrorBox("error", "请选择正确数据");
		companyProvinceDataValidation.setShowErrorBox(true);
		sheet.addValidationData(companyProvinceDataValidation);


		//设置sheet是否隐藏  true:隐藏/false:显示
		workbook.setSheetHidden(workbook.getSheetIndex(hidden), true);

//		XSSFDataValidationHelper dvHelper = new XSSFDataValidationHelper(sheet);
//		XSSFDataValidationConstraint dvConstraint = (XSSFDataValidationConstraint) dvHelper.createExplicitListConstraint(brands);
//		// 四个参数依次的意思是：开始行，结束行，开始列，结束列
//		CellRangeAddressList addressList =  new CellRangeAddressList(3, maxRow, 8, 8);
//		XSSFDataValidation validation  = (XSSFDataValidation) dvHelper.createValidation(dvConstraint, addressList);
//		validation.setErrorStyle(DataValidation.ErrorStyle.STOP);
//		// 当单元格中的值不是下拉选中的值的一个提示
//		validation.createErrorBox("出错啦", "请选择正确的品牌！");
//		// 鼠标移到单元格上的提示
//		validation.createPromptBox("提示", "请选择品牌！");
//		validation.setShowErrorBox(true);
//		validation.setShowPromptBox(true);
//		sheet.addValidationData(validation);

		// 设置行高
		for (int r = 0; r < maxRow; r++) {
			XSSFRow row = sheet.createRow(r + 3);
			row.setHeightInPoints(20);
		}

		//移除workbook中的模板sheet
		workbook.removeSheetAt(0);
		//给sheet命名
		workbook.setSheetName(0, elevatorTemplate.getId().toString());
		return workbook;
	}

	/**
	 * 从某行开始，清除固定行（清除样式）
	 *
	 * @param sheet
	 * @param startRow
	 * @param endRow
	 */
	private void removeRow(XSSFSheet sheet, int startRow, int endRow) {
		for (int j = endRow; j >= startRow; j--) {
			if (sheet.getRow(j) == null) {
				continue;
			}
			sheet.removeRow(sheet.getRow(j));
		}
	}

	public static void main(String[] args) {
		System.err.println(DateUtil.today());
	}
}

